package com.ylr.common;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;

import org.springframework.core.io.ClassPathResource;
//import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
//import org.springframework.security.core.userdetails.UserDetailsService;


import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;

/**
 * @ClassName AuthorizationConfig
 * @Description TODO
 * @Author 11
 * @Date 2021/4/14 21:29
 * @Version 1.0
 */

/**
 * 1.  @EnableAuthorizationServer 注解并继承AuthorizationServerConfigurerAdapter来配置OAuth2.0 授权
 * 服务器。
 */
@EnableAuthorizationServer
@Configuration
public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
    /**
     * ClientDetailsServiceConfigurer：用来配置客户端详情服务（ClientDetailsService），客户端详情信息在
     * 这里进行初始化，你能够把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息。
     * AuthorizationServerEndpointsConfigurer：用来配置令牌（token）的访问端点和令牌服务(token
     * services)。
     * AuthorizationServerSecurityConfigurer：用来配置令牌端点的安全约束.
     */
    @Autowired
    public PasswordEncoder passwordEncoder ;//密码加密器

    @Autowired
    private AuthenticationManager authenticationManager ;//验证管理器


       //userServiceDetailsServiceImpl    inMemoryUserDetailsManager


    @Qualifier("userServiceDetailsServiceImpl")
    @Autowired
    private UserDetailsService userDetailsService ;
//
//    @Autowired   //注入redis连接工厂类
//    private RedisConnectionFactory redisConnectionFactory ;

    /**
     * 添加第三方的客户端  客户端详情服务
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        /**
         * 而ClientDetails有几个重要的属性如下列表：
         * clientId：（必须的）用来标识客户的Id。
         * secret：（需要值得信任的客户端）客户端安全码，如果有的话。
         * scope：用来限制客户端的访问范围，如果为空（默认）的话，那么客户端拥有全部的访问范围。
         * authorizedGrantTypes：此客户端可以使用的授权类型，默认为空。五种该client允许的授权类型
         * authorization_code授权码模式,password密码模式,refresh_token刷新token,implicit,client_credentials客户端模式
         * authorities：此客户端可以使用的权限（基于Spring Security authorities）。
         */

        clients.inMemory()//使用内存保存
                .withClient("coin-api") // 第三方客户端的名称  id
                .secret(passwordEncoder.encode("coin-secret")) //  第三方客户端的密钥
                .scopes("all") //第三方客户端的授权范围
                .authorizedGrantTypes("password","refresh_token")
                .accessTokenValiditySeconds(7 * 24 *3600) // token的有效期
                .refreshTokenValiditySeconds(30 * 24 * 3600)// refresh_token的有效期
                .and()//增加客户端
                .withClient("inside-app")//username
                .secret(passwordEncoder.encode("inside-secret"))//password
                .authorizedGrantTypes("client_credentials")
                .scopes("all")
//                .accessTokenValiditySeconds(7 * 24 *3600)
                .accessTokenValiditySeconds(Integer.MAX_VALUE)//不过期
        ;
        super.configure(clients);

    }


    /**
     * 配置验证管理器，UserdetailService  用来配置令牌（token）的访问端点和令牌服务
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        /**
         * authenticationManager：认证管理器，当你选择了资源所有者密码（password）授权类型的时候，请设置
         * 这个属性注入一个 AuthenticationManager 对象。
         */
        endpoints.authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
//                .tokenStore(redisTokenStore())
//        ;
                .tokenStore(jwtTokenStore())// tokenStore 来存储我们的token jwt 存储token
                .tokenEnhancer(jwtAccessTokenConverter());//转化器把Authorization转成json

        super.configure(endpoints);
    }

//
//    public TokenStore redisTokenStore(){
//        return new RedisTokenStore(redisConnectionFactory) ;
//    }


    private TokenStore jwtTokenStore() {
        JwtTokenStore jwtTokenStore = new JwtTokenStore(jwtAccessTokenConverter());
        return jwtTokenStore;
    }

    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter tokenConverter = new JwtAccessTokenConverter();

        // 加载我们的私钥
        ClassPathResource classPathResource = new ClassPathResource("watchTogether.jks");
        KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(classPathResource, "123456".toCharArray());//(Resource resource, char[] password
        tokenConverter.setKeyPair(keyStoreKeyFactory.getKeyPair("watchTogether", "123456".toCharArray()));//String alias, char[] password
        return tokenConverter;
    }

//
//
//    /**
//     * 配置第三方客户端
//     */
//    @Override
//    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//        clients.inMemory()
//                .withClient("coin-api")
//                .secret(passwordEncoder.encode("coin-secret"))
//                .scopes("all")
//                .authorizedGrantTypes("password","refresh")
//                .accessTokenValiditySeconds(24 * 7200)
//                .refreshTokenValiditySeconds(7 *  24 * 7200) ;
//    }

//    /**
//     * 设置授权管理器和UserDetailsService
//     * @param endpoints
//     * @throws Exception
//     */
//    @Override
//    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//        endpoints.tokenStore(new InMemoryTokenStore())
//                .authenticationManager(authenticationManager)
//                .userDetailsService(userDetailsService) ;
//    }
//


}
